
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;

public class GameController {

    private AgentDispatcher ad;
    private XYToLatLngConverter latLngConverter;
    // Don't know if this should go here or not. We can move it if we need to.
    private KnowledgeBase playerKb;
    private long currentTime;

    public int startGame(double startLng, double startLat, int nAgents, int nVars) {
    	currentTime = System.currentTimeMillis();
        ad = new AgentDispatcher();
        latLngConverter = new XYToLatLngConverter(startLat, startLng);
        playerKb = new KnowledgeBase();
        ArrayList<Agent> ags = ad.generateAgents(nAgents);
//        int a = Global.getKiller(ags);
//        Agent first = ags.get(0);
//        ags.set(0, ags.get(a));
//        ags.set(a, first);
        Global.agents = ags;

        for (int i = 0; i < Global.agents.size(); i++) {
            Global.agents.get(i).start();
        }
        return 1;
    }

    public ArrayList<AgentLocDto> getAgentLocs() {
    	long elapsedTime = System.currentTimeMillis() - currentTime;
    	elapsedTime /= 1000;
    	
        AgentLocDto[] agentLocs = new AgentLocDto[Global.agents.size()];
        ArrayList<Agent> shuffledAgents = new ArrayList<Agent>(Global.agents);
        Collections.shuffle(shuffledAgents);
        
        for (int i=0 ; i<((int)Math.floor(elapsedTime/Global.TIME_STEP))-1; i++) {
        	for (Agent agent : shuffledAgents) {
        		agent.step();
        	}
        }
        for (Agent agent : shuffledAgents) {
            //agent.updateLocation();
            agent.step();
            LatLng latlng = latLngConverter.xyToLatLng(agent.getLocx(), agent.getLocy());
            AgentLocDto dto = new AgentLocDto();
            dto.setId(agent.getAgentid());
            dto.setLat(latlng.getLat());
            dto.setLng(latlng.getLng());
            dto.setName(agent.getAgentname());
            dto.setAlive(agent.isLiving());
            agentLocs[agent.getAgentid()] = dto;
        }
        currentTime = System.currentTimeMillis();
        return new ArrayList<AgentLocDto>(Arrays.asList(agentLocs));
    }

    public AgentDto getAgentDetails(final String name) {
        // This could be more efficient if the global agents was a hashmap instead of an array.
        // Doesn't really matter much though.
        for (Agent agent : Global.agents) {
            if (agent.getAgentname().equalsIgnoreCase(name)) {
                AgentDto dto = new AgentDto();
                dto.setAgentid(agent.getAgentid());
                dto.setAgentname(agent.getAgentname());
                dto.setLikes(playerKb.getLikes(agent.getAgentid()));
                dto.setDislikes(playerKb.getDislikes(agent.getAgentid()));
                dto.setFriends(playerKb.getFriends(agent.getAgentid()));
                dto.setLiving(agent.isLiving());
                return dto;
            }
        }
        return null; // this shouldn't really happen.
    }

    private Agent getAgentByName(final String agentName) {
        // Again, this is terribly inefficient
        Agent agent = null;
        for (Agent tempAgent : Global.agents) {
            if (tempAgent.getAgentname().equalsIgnoreCase(agentName)) {
                agent = tempAgent;
                break;
            }
        }
        return agent;
    }

    public String askQuestion(final String agentName, final String questionType) {
        QuestionType typeEnum = QuestionType.to(questionType);

        // Again, this is terribly inefficient
        Agent agent = getAgentByName(agentName);
        boolean trust = getTrust(agentName);
        boolean isValuable = true;
        String variable = "";
        Answer answer = new Answer();
        answer.setAgentId(agent.getAgentid());
        Random r = new Random();
        //Answer answer = agent.askQuestion(typeEnum);
        //Ask for a recent event.
        if (typeEnum.equals(QuestionType.EVENT)) {
            if (agent.myEvents.isEmpty()) {
                variable = "has not heard anything new recently";
                isValuable = false;
                answer.setType(AnswerType.EVENT);
            } else {
                int ra = r.nextInt(agent.myEvents.size());
                while (agent.myEvents.get(ra).type.equals("Guess")) {
                    ra = r.nextInt(agent.myEvents.size());
                }
                Event event = agent.myEvents.get(ra);
                Agent vict = Global.agents.get(event.getVictimid());        
                    int r1 = r.nextInt(vict.likes.size());
                    variable = vict.likes.get(r1);
                    answer.setType(AnswerType.LIKE);
                answer.setAgentId(vict.getAgentid());
                if (!event.getType().equalsIgnoreCase("gossip")) {
                    playerKb.addFriend(vict.getAgentid(), agent.getAgentid());
                }
            }
        } //Ask for personal question.
        else if (typeEnum.equals(QuestionType.PERSONAL)) {
            boolean rb = r.nextBoolean();
            if (rb) {
                int r1 = r.nextInt(agent.likes.size());
                variable = agent.likes.get(r1);
                answer.setType(AnswerType.LIKE);
            } else {
                int r1 = r.nextInt(agent.dislikes.size());
                variable = agent.dislikes.get(r1);
                answer.setType(AnswerType.DISLIKE);
            }
        } //Ask for a theory
        else {
            int susp = Global.makeGuess(agent.agentid);
            if (susp == -1) {
                variable = "no one in particular";
                isValuable = false;
            } else {
                variable = Global.agents.get(susp).agentname;
            }
            answer.setType(AnswerType.THEORY);
        }
        answer.setVariable(variable);
       if(trust){
            if (isValuable) {
                playerKb.addAnswer(answer);
            }}
       else{
           answer.setVariable("I don't trust you, please try again!");
       }
          
        return answer.getDisplayableString();
    }

    public String getQuestion(final String agentName) {
        Agent agent = getAgentByName(agentName);
        Random r = new Random();
        boolean rb = r.nextBoolean();
        String question = "";
        if (rb) {
            int rand = r.nextInt(agent.likes.size());
            question = agent.likes.get(rand);
        } else {
            int rand = r.nextInt(agent.dislikes.size());
            question = agent.dislikes.get(rand);
        }
        return question;
    }

    /**
     * Answers a question asked by an agent.
     * 
     * @param agentName the name of the agent who asked the question
     * @param question The question variable, like "cats" or "dogs"
     * @param answer The answer. Either "yes" or "no"
     * 
     * @return True if the agent agrees with your response. False otherwise.
     */
    public boolean answerQuestion(final String agentName, final String question, final String answer) {
        Agent agent = getAgentByName(agentName);
        boolean b = true;
        if (agent.likes.contains(question)) {
            if (answer.equalsIgnoreCase("yes")) {
                agent.answers.add(true);
                b= true;
            } else {
                agent.answers.add(false);
                b= false;
            }
        } else if(agent.dislikes.contains(question)){
            if (answer.equalsIgnoreCase("yes")) {
                agent.answers.add(true);
                b= true;
            } else {
                
                agent.answers.add(false);
                b= false;
            }
        }
        return b;
    }
    
    /**
     * This gets agent details for every agent.
     * @return
     */
    public List<Agent> getAgentList() {
        return Global.agents;
    }

    public int getTotalEnemies() {
        for (Agent agent : Global.agents) {
            if (agent.isKiller()) {
                return agent.getEnemies().size();
            }
        }
        return 0;
    }

    public String getLivingRatio() {
        int totalSize = 0;
        int dead = 0;
        for (Agent agent : Global.agents) {
            if (agent.isKiller()) {
                totalSize = agent.getEnemies().size();
            }
            if (!agent.isLiving()) {
                dead++;
            }
        }
        return (totalSize - dead) + " of " + totalSize;
    }
    public boolean getTrust(final String agentName){
    Agent a = getAgentByName(agentName);
    boolean trust = false;
    if(a.answers.isEmpty()){
    trust = false;
    }
    else{
    trust = a.answers.get(a.answers.size()-1);
    }
    return trust; 
    }
    public String getKillerName() {
        Agent agent = null;
        for (Agent tempAgent : Global.agents) {
            if (tempAgent.isKiller()) {
                agent = tempAgent;
                return agent.getAgentname();
            }
        }
        return "";
    }
}
